/*
 * Copyright 2025 The JA-SIG Collaborative. All rights reserved.
 * distributed with this file and available online at
 */
package com.lap.auth.application.menu.assembler;

import com.lap.auth.application.menu.command.CreateMenuCmd;
import com.lap.auth.application.menu.command.UpdateMenuCmd;
import com.lap.auth.application.menu.dto.MenuNodeDto;
import com.lap.auth.domain.menu.Menu;
import com.lap.auth.domain.menu.valueobject.MenuType;
import com.lap.auth.shared.tools.BaseConverter;
import com.lap.framework.common.tool.BooleanStrategy;
import com.lap.framework.common.tool.EnumUtil;
import java.util.*;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper(componentModel = "spring")
public interface MenuAssembler extends BaseConverter {

  Integer ZERO = 0;

  @Mapping(target = "event",  ignore = true)
  @Mapping(target = "createdBy",  ignore = true)
  @Mapping(target = "createTime", ignore = true)
  @Mapping(target = "id", ignore = true)
  Menu toDomain(CreateMenuCmd cmd);

  @Mapping(target = "createTime", ignore = true)
  @Mapping(target = "id", source = "id")
  Menu toDomain(Integer id, UpdateMenuCmd cmd);

  @Mapping(target = "children", ignore = true)
  MenuNodeDto toDto(Menu menu);

  List<MenuNodeDto> toDtoList(List<Menu> list);

  default MenuType codeToMenuType(Integer code) {
    return EnumUtil.fromCode(MenuType.class, code);
  }

  default Integer menuTypeToCode(MenuType type) {
    return type.getCode();
  }

  default Integer boolToInt(Boolean bool) {
    return BooleanStrategy.toInt(bool);
  }

  default boolean intToBool(Integer bool) {
    return BooleanStrategy.toBool(bool);
  }

  default List<MenuNodeDto> convertToTree(List<MenuNodeDto> allList) {
    List<MenuNodeDto> roots = new ArrayList<>();
    Map<Integer, MenuNodeDto> nodeMap = new HashMap<>();
    for (MenuNodeDto dto : allList) {
      dto.setChildren(new ArrayList<>());
      nodeMap.put(dto.getId(), dto);
    }

    for (MenuNodeDto dto : allList) {
      if (dto.getParentId() == null || Objects.equals(dto.getParentId(), ZERO)) {
        roots.add(dto);
      } else {
        MenuNodeDto parent = nodeMap.get(dto.getParentId());
        if (parent != null) {
          parent.getChildren().add(dto);
        }
      }
    }

    for (MenuNodeDto dto : nodeMap.values()) {
      dto.getChildren().sort(Comparator.comparing(MenuNodeDto::getRank));
    }
    roots.sort(Comparator.comparing(MenuNodeDto::getRank));
    return roots;
  }
}
